/*
 * SoulFire
 * Copyright (C) 2024  AlexProgrammerDE
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
package com.soulfiremc.mod.mixin.soulfire.api.event;

import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.soulfiremc.server.api.SoulFireAPI;
import com.soulfiremc.server.api.event.DummyPacket;
import com.soulfiremc.server.api.event.bot.BotPacketPreReceiveEvent;
import com.soulfiremc.server.api.event.bot.BotPacketPreSendEvent;
import com.soulfiremc.server.bot.BotConnection;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import net.minecraft.network.Connection;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.network.protocol.game.ClientboundBundlePacket;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable;

import java.util.ArrayList;

@Mixin(Connection.class)
public class MixinConnection {
  @Shadow
  private Channel channel;

  @SuppressWarnings("unchecked")
  @ModifyVariable(method = "genericsFtw", at = @At("HEAD"), argsOnly = true)
  private static Packet<?> handlePacket(Packet<?> parentPacket) {
    var connection = BotConnection.CURRENT.get();
    if (parentPacket instanceof ClientboundBundlePacket bundlePacket) {
      var subPackets = new ArrayList<Packet<? super ClientGamePacketListener>>();

      for (var subPacket : bundlePacket.subPackets()) {
        var event = new BotPacketPreReceiveEvent(connection, subPacket);
        SoulFireAPI.postEvent(event);

        if (event.packet() != null) {
          subPackets.add((Packet<? super ClientGamePacketListener>) event.packet());
        }
      }

      return new ClientboundBundlePacket(subPackets);
    } else {
      var event = new BotPacketPreReceiveEvent(connection, parentPacket);
      SoulFireAPI.postEvent(event);

      if (event.packet() != null) {
        return event.packet();
      } else {
        return new DummyPacket();
      }
    }
  }

  @WrapMethod(method = "doSendPacket")
  public void wrapDoSendPacket(Packet<?> packet, @Nullable ChannelFutureListener sendListener, boolean flush, Operation<Void> original) {
    var connection = BotConnection.CURRENT.get();
    var event = new BotPacketPreSendEvent(connection, packet);
    SoulFireAPI.postEvent(event);

    if (event.packet() != null) {
      original.call(event.packet(), sendListener, flush);
    } else {
      if (sendListener != null) {
        try {
          sendListener.operationComplete(channel.newSucceededFuture());
        } catch (Exception e) {
          throw new RuntimeException(e);
        }
      }

      if (flush) {
        channel.flush();
      }
    }
  }
}
